#include "config.h"
#include "mips-formats.h"
#include "opcode/mips.h"
#include "mips-regdef.h"
#include <stdio.h>
#include <ctype.h>
#include "instrs-fmt.h"
#define LD_ST (INSN_LOAD_MEMORY | INSN_STORE_MEMORY)
#define CP_LD_ST (INSN_LOAD_COPROC | INSN_COPROC_MOVE)
#define BRANCH_INS  (INSN_UNCOND_BRANCH_DELAY | INSN_COND_BRANCH_DELAY | INSN_UNCOND_BRANCH_DELAY | INSN_COND_BRANCH_LIKELY)

void dump_opcode(int pinfo)
{
    for(int i = 0;i < bfd_mips_num_builtin_opcodes;i++) {
        struct mips_opcode *op = &mips_opcodes[i];

        if(opcode_is_member(op, ISA_MIPS32R2, 0, CPU_R3000)){

            if((op->pinfo &
                (INSN_UDI | INSN_TLB | INSN_COP | INSN_NO_DELAY_SLOT | INSN_NO_DELAY_SLOT) ) == 0) {
                if(op->ase == 0) {
                    if(op->pinfo & pinfo) {
                        printf("\t%s %s 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
                               op->name,op->args,
                               op->match,op->mask,op->pinfo,op->pinfo2,
                               op->membership,op->ase,op->exclusions);
                    }
                }
            }
        }
    }
}



void dump_all_regs()
{
    for(int  i = 0;i < regname_size;i++){
        printf("%s\n",regname[i]);
    }
}

char* strToUpper(char *str) {

    for (int i = 0; str[i]; ++i) {
        str[i] = toupper((unsigned char)str[i]);
    }
    return str;
}

void dump_generic_regs()
{
    char str[20];
    for(int i = 0;i < mips_greg_num.nums;i++) {
        strcpy(str,GET_GREGNAME(i));
        printf("MIPS32_%s = %d,\n",strToUpper(str),i);
    }
}

void dump_float_regs()
{
    char str[20];
    for(int i = 0;i < mips_freg_num.nums;i++) {
        strcpy(str,GET_FREGNAME(i));
        printf("MIPS32_%s = %d,\n",strToUpper(str),i);
    }

    for(int i = 0;i < mips_freg_num.rets;i++) {
        strcpy(str,GET_FREG(ret,i));
        printf("MIPS32_FR%d = MIPS32_%s,\n",i,strToUpper(str));
    }

    for(int i = 0;i < mips_freg_num.args;i++) {
        strcpy(str,GET_FREG(arg,i));
        printf("MIPS32_FA%d = MIPS32_%s,\n",i,strToUpper(str));
    }

    for(int i = 0;i < mips_freg_num.callers;i++) {
        strcpy(str,GET_FREG(caller,i));
        printf("MIPS32_FT%d = MIPS32_%s,\n",i,strToUpper(str));
    }

    for(int i = 0;i < mips_freg_num.callees;i++) {
        strcpy(str,GET_FREG(callee,i));
        printf("MIPS32_FS%d = MIPS32_%s,\n",i,strToUpper(str));
    }
}

int main(int argc,char* argv[])
{
    printf("load store code:\n");
    dump_opcode(LD_ST);
    printf("brach code:\n");
    dump_opcode(BRANCH_INS);
    dump_all_regs();
    dump_generic_regs();
    dump_float_regs();
    dump_opcode_r_type();
    dump_opcode_r4_type();
    dump_opcode_f_type();
    dump_opcode_i_type();
    dump_opcode_j_type();
    gen_test_code();
}
